#!/usr/bin/python3
# -*- coding: utf-8 -*-
# 获取当前脚本文件所在目录的父目录，并构建相对路径
import os
import sys
current_dir = os.path.dirname(os.path.abspath(__file__))
project_path = os.path.join(current_dir, '.')
common_path = os.path.join(project_path, 'common')
sub_path = os.path.join(project_path, 'sub')
sys.path.append(project_path)
sys.path.append(current_dir)
sys.path.append(sub_path)
sys.path.append(common_path)
import json
import serial
import threading
import struct
from pymodbus.server.sync import StartSerialServer
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer
from serial import Serial
from pymodbus.datastore import ModbusSequentialDataBlock

# 定义要维护的寄存器的初始值[0~255]
# 定义要维护的寄存器的初始值
hr_block = ModbusSequentialDataBlock(0, [0] * 0x10000)  # Holding Register
block = ModbusSlaveContext(hr=hr_block)
store = ModbusServerContext(slaves=block, single=True)

import ctypes
import threading
import ctypes.util

# 定义调用的 C 库函数
libc = ctypes.CDLL(ctypes.util.find_library('c'))
pthread_setschedparam = libc.pthread_setschedparam
pthread_setschedparam.argtypes = [ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(ctypes.c_void_p)]

def set_thread_priority(thread_id, priority):
    param = ctypes.c_void_p()
    param.value = priority
    pthread_setschedparam(thread_id, 0, ctypes.byref(param))

import ctypes
import threading

def terminate_thread(thread):
    if not thread.is_alive():
        return

    # 终止线程的函数定义
    def _async_raise(tid, exctype):
        """raises the exception, performs cleanup if needed"""
        tid = ctypes.c_long(tid)
        if ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)):
            return
        raise ValueError("invalid thread id")

    thread_id = thread.ident
    _async_raise(thread_id, SystemExit)

class GpModbus:
    def __init__(self):
        self.modbusIf = None
        self.serial_thread = None
        self.modbusIf = block
        self.modbusAddress = None, 
        self.serialPortDevPath = None, 
        self.serial_baud = None
    
    def startModbusSlave(self, modbusAddress, serialPortDevPath, serial_baud):
        if isinstance(modbusAddress, tuple):
           modbusAddress = modbusAddress[0]
        if isinstance(serialPortDevPath, tuple):
           serialPortDevPath = serialPortDevPath[0]
        print(f'start modbus slave: {modbusAddress}, {serialPortDevPath}, {serial_baud}');
        self.modbusAddress = modbusAddress, 
        self.serialPortDevPath = serialPortDevPath, 
        self.serial_baud = serial_baud
        
        # 创建线程并启动
        self.serial_thread = threading.Thread(target=self.startModbusSlave_ThenBlock, args=[modbusAddress, serialPortDevPath, serial_baud])
        self.serial_thread.start()
        # 获取线程 ID
        #thread_id = self.serial_thread.ident
        # 设置线程的优先级
        #set_thread_priority(thread_id, 90) # 优先级值可以根据具体需求调整

    #address is u16 serial, serialPortDevPath="" means using 虚拟串口
    #禁止使用，应当使用startModbusSlave
    def startModbusSlave_ThenBlock(self, modbusAddress, serialPortDevPath, serial_baud):
        # 配置虚拟串口
        try:
            serialPort = None
            #print(f"start modbus slave {serialPortDevPath} - {serial_baud}")
            if(serialPortDevPath is not None):
                # 启动 Modbus RTU 从机
                server = StartSerialServer(context=store, identity=None, framer=ModbusRtuFramer, 
                    port=serialPortDevPath, 
                    baudrate=serial_baud,
                    bytesize=8,  # ASCII 通常使用 7 位数据位
                    parity='N',  # ASCII 通常使用偶校验
                    stopbits=1,
                    timeout=0.02,
                    broadcast_enable=True) #可以向用户广播
                server.start()
        except Exception as e:
            print('gpModbus_startVirtualModbusSlave()', e)
        print(f"self.modbusIf = {block}")

        try:
            while True:
                pass
        except KeyboardInterrupt:
            print("程序已停止")
    
    # 模拟寄存器读 0,123
    def write_register(self, register_addr, register_value):
       self.write_hold_register(register_addr, register_value)

    # 模拟寄存器读 0,123
    def write_registers(self, register_addr, register_values):
       self.write_hold_register(register_addr, register_value) 

    def gpU16ToReversed(self, value):
        if isinstance(value, list):
            ret = [self.gpU16ToReversed(elem) for elem in value]
        else:
            ret = struct.unpack('>H', struct.pack('<H', value))[0]
        return ret


    # 模拟保持寄存器写[resiter_value可以为数组]
    def write_hold_register(self, register_addr, register_value):
        try:
            #regisgter_addr_reversed = self.gpU16ToReversed(register_addr)
            #register_value_reversed = self.gpU16ToReversed(register_value)
            if isinstance(register_value, list):
                print(f'addr:{register_addr}, {register_value}, cnt={len(register_value)}')
                hr_block.setValues(register_addr+1, register_value)  # 获取 Holding Registers 的值
            else:
                print(f'addr:{register_addr}, {register_value}, cnt=1')
                hr_block.setValues(register_addr+1, [register_value])  # 获取 Holding Registers 的值
        except Exception as e:
            print(f'write register error {e}');

    def read_hold_registers(self, register_addr, nCnt):
        try:
            print(f'read:{self.modbusIf} {register_addr},cnt={nCnt}')
            if(self.modbusIf is None):
                return [];
            return hr_block.getValues(register_addr+1, nCnt)  # 获取 Holding Registers 的值
        except Exception as e:
            print(f'read_register register error{e}');
        return []
